import re
import xml.sax.handler
import httplib
import urllib
import socket

#Please post me back your comments and issues krishgy@gmail.com

#Truveo is a great video search engine, here is an attempt to use use them through python

#TODO: 1. Error handling
#TODO: 2. Documentation
#TODO: 3. Code cleanup  (removal of print, .. etc)
#TODO: 4. Unit test

#copied from receipe ActiveStae site
#Many thanks to Wai Yip Tung for his receipe in http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/534109
#I changed the function  name
#TODO: Should I need this function here?
def xml_to_python(src):
    """
    A simple function to converts XML data into native Python object.
    """

    non_id_char = re.compile('[^_0-9a-zA-Z]')
    def _name_mangle(name):
        return non_id_char.sub('_', name)

    class DataNode(object):
        def __init__(self):
            self._attrs = {}    # XML attributes and child elements
            self.data = None    # child text data
        def __len__(self):
            # treat single element as a list of 1
            return 1
        def __getitem__(self, key):
            if isinstance(key, basestring):
                return self._attrs.get(key,None)
            else:
                return [self][key]
        def __contains__(self, name):
            return self._attrs.has_key(name)
        def __nonzero__(self):
            return bool(self._attrs or self.data)
        def __getattr__(self, name):
            if name.startswith('__'):
                # need to do this for Python special methods???
                raise AttributeError(name)
            return self._attrs.get(name,None)
        def _add_xml_attr(self, name, value):
            if name in self._attrs:
                # multiple attribute of the same name are represented by a list
                children = self._attrs[name]
                if not isinstance(children, list):
                    children = [children]
                    self._attrs[name] = children
                children.append(value)
            else:
                self._attrs[name] = value
        def __str__(self):
            return self.data or ''
        def __repr__(self):
            items = sorted(self._attrs.items())
            if self.data:
                items.append(('data', self.data))
            return u'{%s}' % ', '.join([u'%s:%s' % (k,repr(v)) for k,v in items])

    class TreeBuilder(xml.sax.handler.ContentHandler):
        def __init__(self):
            self.stack = []
            self.root = DataNode()
            self.current = self.root
            self.text_parts = []
        def startElement(self, name, attrs):
            self.stack.append((self.current, self.text_parts))
            self.current = DataNode()
            self.text_parts = []
            # xml attributes --> python attributes
            for k, v in attrs.items():
                self.current._add_xml_attr(_name_mangle(k), v)
        def endElement(self, name):
            text = ''.join(self.text_parts).strip()
            if text:
                self.current.data = text
            if self.current._attrs:
                obj = self.current
            else:
                # a text only node is simply represented by the string
                obj = text or ''
            self.current, self.text_parts = self.stack.pop()
            self.current._add_xml_attr(_name_mangle(name), obj)
        def characters(self, content):
            self.text_parts.append(content)

    builder = TreeBuilder()
    if isinstance(src,basestring):
        xml.sax.parseString(src, builder)
    else:
        xml.sax.parse(src, builder)
    return builder.root._attrs.values()[0]

"""
"""
class Truveo:
    def __init__(self, appid, site = 'xml.truveo.com', path = '/apiv3?', port = 80):
        self.appid = appid
        self.site  = site
        self.path  = path
        self.port  = port        
    
    def get_videos(self, parameters):
        parameters["method"] = "truveo.videos.getVideos"
        return self.rest(parameters)        
    
    def get_related(self, query_type, parameters):
        parameters["method"] = "truveo.videos.getRelated"+query_type
        return self.rest(parameters)        
    
    def get_related_tags(self, parameters):        
        return self.get_related("Tags", parameters)
    
    def get_related_channels(self, parameters):
        return self.get_related("Channels", parameters)
    
    def get_related_users(self, parameters):
        return self.get_related("Users", parameters)
        
    def get_related_categories(self, parameters):
        return self.get_related("Categories", parameters)
        
    def rest(self, parameters):
        query = ""
        parameters["appid"] = self.appid
        query = urllib.urlencode(parameters)
        url = self.path + query
        headers = {'Accept': 'text/plain'}
        
        try:
            conn = httplib.HTTPConnection(self.site)
            req = conn.request('GET', self.path + query, {}, headers)
        except socket.error:
            print "Can't connect to server: " + self.site
            return 0, ""
        
        res = conn.getresponse()
        status = res.status
        content = res.read()
        
        conn.close()
        
        if status != 200:
            print "Error! Status returned: %(status)s" % {"status" : status }
            return 0, ""
        
        response = xml_to_python(content)
        
        return status, response

        
# Example for how to use Python Truveo API
if __name__ == '__main__':
    truveo = Truveo("__YOUR_API_KEY_FOR_TRUVEO")
    query = {'query':'funny'}
    (status, response) = truveo.get_videos(query)
    if status == 200:
        print response.method
        print response.VideoSet.totalResultsReturned
        print response.VideoSet.totalResultsAvailable
        for video in response.VideoSet.Video:
            print video.title
    
    query = {'query':'james'}
    (status, response) = truveo.get_related_users(query)
    if status == 200:
        print response.method
        print response.UserSet.totalResultsReturned
        print response.UserSet.totalResultsAvailable
        for user in response.UserSet.User:
            print user.name

    (status, response) = truveo.get_related_tags(query)
    query = {'query':'fox'}
    if status == 200:
        print response.method
        print response.TagSet.totalResultsReturned
        print response.TagSet.totalResultsAvailable
        for tag in response.TagSet.Tag:
            print tag.name
            
    (status, response) = truveo.get_related_channels(query)
    
    if status == 200:
        print response.method
        print response.ChannelSet.totalResultsReturned
        print response.ChannelSet.totalResultsAvailable
        for channel in response.ChannelSet.Channel:
            print channel.name
    
    query = {'query':'animals'}
    (status, response) = truveo.get_related_categories(query)
    
    if status == 200:
        print response.method
        print response.CategorySet.totalResultsReturned
        print response.CategorySet.totalResultsAvailable
        for category in response.CategorySet.Category:
            print category.name
    